package com.hitqz.robot.biz.controller;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.FileAppender;
import cn.hutool.core.io.IoUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.hitqz.robot.admin.api.dto.RequireClientLogDto;
import com.hitqz.robot.common.file.core.FileProperties;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.cache.Cache;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Objects;

/**
 * @author xupkun
 * @date 2024/12/4
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/timelyLog")
@Tag(name = "实时日志")
@Slf4j
public class LogController {

    private final FileProperties properties;

    @GetMapping(value = "downLogs")
    @Operation(summary = "下载日志文件", description = "下载日志文件")
    public ResponseEntity<Resource> downloadLogs(@RequestParam(value = "clientId", required = true) String clientId) {
        log.info("Downloading logs request for client " + clientId);
        String targetLog = "";
        if (clientId.equals("server")) {
            LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
            FileAppender fileAppender = (FileAppender) loggerContext.getLogger("ROOT").getAppender("info");
            if (fileAppender!= null) {
                String logFilePath = System.getProperty("user.dir") + File.separator + fileAppender.getFile().replace("/info.log", "");
                targetLog = System.getProperty("java.io.tmpdir") + File.separator + "log.zip";
                File targetLogFile = new File(targetLog);
                if (targetLogFile.exists()) {
                    targetLogFile.deleteOnExit();
                }
                compressFolderWithCommonsCompress(logFilePath, targetLog);
            }
        } else {
            RequireClientLogDto requireLogDto = new RequireClientLogDto();
            requireLogDto.setClientId(clientId);
            SpringUtil.getApplicationContext().publishEvent(requireLogDto);
            while(true) {
                Cache<String, String> posInfoDtoCache = SpringUtil.getBean("uploaderLogs");
                if (posInfoDtoCache.getIfPresent(clientId) != null) {
                    targetLog = properties.getLocal().getBasePath() +
                            Objects.requireNonNull(posInfoDtoCache.getIfPresent(clientId)).replace("admin/sys-file/", "");
                    break;
                }
            }
        }
        // /admin/sys-file/local/patrol/2024-12-05/9d33809a82ed44b1a1a0a9fa8188239d.jpg
        File targetLogFile = new File(targetLog);
        if (targetLogFile.exists()) {
            HttpHeaders headers = new HttpHeaders();
            headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
            headers.add("Pragma", "no-cache");
            headers.add("Expires", "0");
            headers.add("Content-Disposition", "attachment; filename=logs.zip");
            FileSystemResource resource = new FileSystemResource(targetLogFile);
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(targetLogFile.length())
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);
        }
        return ResponseEntity.notFound().build();
    }



    public static void compressFolderWithCommonsCompress(String sourceFolderPath, String zipFilePath) {
        try (ZipArchiveOutputStream zipOut = new ZipArchiveOutputStream(new FileOutputStream(zipFilePath))) {
            zipOut.setUseZip64(Zip64Mode.AsNeeded);
            compressFolderHelperWithCommonsCompress(sourceFolderPath, "", zipOut);
            zipOut.finish();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void compressFolderHelperWithCommonsCompress(String folderPath, String parentPath, ZipArchiveOutputStream zipOut) throws IOException {
        File folder = new File(folderPath);
        if (folder.isDirectory()) {
            File[] files = folder.listFiles();
            if (files!= null) {
                for (File file : files) {
                    String filePath = parentPath + file.getName() + "/";
                    if (file.isDirectory()) {
                        ZipArchiveEntry zipEntry = new ZipArchiveEntry(filePath);
                        zipOut.putArchiveEntry(zipEntry);
                        zipOut.closeArchiveEntry();
                        compressFolderHelperWithCommonsCompress(file.getAbsolutePath(), filePath, zipOut);
                    } else {
                        compressFileWithCommonsCompress(file, parentPath, zipOut);
                    }
                }
            }
        }
    }

    private static void compressFileWithCommonsCompress(File file, String parentPath, ZipArchiveOutputStream zipOut) throws IOException {
        FileInputStream fis = new FileInputStream(file);
        ZipArchiveEntry zipEntry = new ZipArchiveEntry(file, parentPath + file.getName());
        zipOut.putArchiveEntry(zipEntry);
        IoUtil.copy(fis, zipOut);
        zipOut.closeArchiveEntry();
        fis.close();
    }

}
